import React, {useEffect, useState} from 'react';
import {Box, Card, CardContent, Chip, IconButton, Stack, Tooltip, Typography} from "@mui/material";
import ToggleButtonGroup from "@mui/material/ToggleButtonGroup";
import ToggleButton from "@mui/material/ToggleButton";
import DialogTitle from "@mui/material/DialogTitle";
import CloseIcon from "@mui/icons-material/Close";
import Dialog from "@mui/material/Dialog";
import {getConfig} from "../../api/lesson/lesson-schedule-config";
import {occupied, save, schedules as getSchedules} from "../../api/lesson/lesson-schedule";
import LoadingButton from "@mui/lab/LoadingButton";
import {Done, SignalCellularAlt} from "@mui/icons-material";
import FaceIcon from '@mui/icons-material/Face';

import CircularProgress from "@mui/material/CircularProgress";

import {confirm} from "../common/confirm";
import {alert} from "../common/alert";

import {getDayOfWeek, WEEK, WORKDAYS} from "../../utils/time";

import Line from "./line";

function ManualSchedule({open, classGroup, thisWeek, onClose}) {

    const [dayOfWeek, setDayOfWeek] = useState(-999);
    const [rest, setRest] = useState(0);

    const [config, setConfig] = React.useState({});
    const [workdays, setWorkdays] = React.useState([...WORKDAYS]);
    const [values, setValues] = React.useState([]);

    const [submitting, setSubmitting] = React.useState(false);

    const [draft, setDraft] = React.useState(true);
    const [published, setPublished] = React.useState(false);
    const [mode, setMode] = React.useState('');

    const [occupiedTimes, setOccupiedTimes] = React.useState([]);

    const [valid, setValid] = React.useState(true);

    // fetch lesson_schedule_config
    useEffect(() => {
        getConfig().then(data => {
            const myConfig = {...data};
            myConfig.available = (workday) => {
                const hours = workday ? myConfig.workdayHour : myConfig.holidayHour;
                const available = [];
                for (let i = 0; i < 24; i++) {
                    if (hours.charAt(i) === '1') {
                        const hour = i < 10 ? `0${i}` : i.toString();
                        if (myConfig.halfHour) {
                            available.push(`${hour}:00`);
                            available.push(`${hour}:30`);
                        } else {
                            available.push(hour);
                        }
                    }
                }
                return available;
            }
            setConfig(myConfig);
        });
    }, []);

    // get occupied times, exist lesson_schedule
    useEffect(() => {
        if (open && classGroup) {

            const published = thisWeek ? classGroup.thisWeek.published : classGroup.nextWeek.published;
            setPublished(published);
            setDraft(true);
            setMode(published === undefined ? '：新建' : '：编辑');

            getSchedules(classGroup.id, thisWeek).then(data => {
                if (data.length > 0) {
                    const newVs = data.reduce((acc, e) => {
                        const lt = new Date(e.lessonTime);
                        const index = getDayOfWeek(lt);
                        if (index <= dayOfWeek) {
                            return acc;
                        }

                        const hours = lt.getHours().toString().padStart(2, '0');
                        const minutes = lt.getMinutes().toString().padStart(2, '0');
                        const t0 = `${hours}:${minutes}`;
                        let t1 = "";
                        if (config.halfHour) {
                            if (minutes === "00") {
                                t1 = `${hours}:30`;
                            } else {
                                const hour1 = (lt.getHours() + 1).toString().padStart(2, '0')
                                t1 = `${hour1}:00`;
                            }
                        }
                        const vs = acc[index];
                        if (Array.isArray(vs)) {
                            vs.push(t0);
                            if (config.halfHour) {
                                vs.push(t1);
                            }
                        } else {
                            acc[index] = config.halfHour ? [t0, t1] : [t0];
                        }
                        return acc;
                    }, []);
                    setValues(newVs);
                }
            });


            occupied(classGroup.id, thisWeek).then(data => {
                const times = data.date.map(e => {
                    const date = new Date(e);
                    const day = getDayOfWeek(date);
                    const hour = date.getHours().toString().padStart(2, '0');
                    const minute = date.getMinutes().toString().padStart(2, '0');
                    return `${day}-${hour}:${minute}`;
                });
                setOccupiedTimes(times);

                const x = classGroup.course.lessonCount - data.maxLessonNumber;
                setRest(config.halfHour ? x * 2 : x);
            });
        }
    }, [open, classGroup, thisWeek, config.halfHour, dayOfWeek]);

    // if switch classGroup, reset values
    useEffect(() => {
        setValues([]);
        setDayOfWeek(thisWeek ? getDayOfWeek() : -999);
    }, [classGroup?.id, thisWeek]);

    // submit button's disabled
    useEffect(() => {
        setValid(values.some(e => Array.isArray(e) && e.length > 0));
    }, [values]);

    // if switch week, reset workdays
    useEffect(() => {
        setWorkdays([...WORKDAYS]);
    }, [thisWeek]);

    function handleClose(event, reason) {
        event.stopPropagation();
        if (reason !== 'backdropClick' && reason !== 'escapeKeyDown') {
            onClose(false);
        }
    }

    function check(index) {
        if (thisWeek && index <= dayOfWeek) {
            return null;
        }

        const value = values[index];
        const length = value === undefined ? 0 : value.length;
        if (length === 0) {
            return null;
        }

        const week = WEEK[index].name;
        const workday = workdays[index];
        if (config.halfHour) {

            let error = "";

            if (length % 2 !== 0) {
                error += `安排了 ${length / 2.0} 节课，不是整数`
            }

            const v = [...value];
            v.sort();
            for (let i = 0; i < length; i += 2) {
                const hour1 = parseInt(v[i].replace(':', ''));
                if (i + 1 >= length) {
                    error += `${error ? "；" : ""}${v[i]}-？时间段不连续`
                    break;
                }
                const hour2 = parseInt(v[i + 1].replace(':', ''));
                if (hour2 - hour1 !== 30 && hour2 - hour1 !== 70) {
                    error += `${error ? "；" : ""}${v[i]}-${v[i + 1]} 时间段不连续`
                }
            }

            const count = length / 2;
            if ((workday && count > 1) || (!workday && count > 2)) {
                error += `${error ? "；" : ""}安排了 ${count} 节课，可能超标`
            }

            return error === "" ? null : `${week}：${error}`;
        }

        if ((workday && length > 1) || (!workday && length > 2)) {
            return `${week}：安排了 ${value.length} 节课，可能超标`
        }
        return null;

    }

    function handleSubmit(event) {
        event.preventDefault();

        const errors =
            WEEK.map(e => check(e.index))
                .filter(e => e !== null);

        (errors.length ? confirm(
                ["检查发现如下问题", ...errors, "请确认是否还要提交？建议取消提交，重新排课。"]) :
            Promise.resolve(true))
            .then(choice => {
                if (choice) {
                    setSubmitting(true);
                    return save({
                        classGroupId: classGroup.id,
                        start: thisWeek ? classGroup.thisWeek.start : classGroup.nextWeek.start,
                        draft, thisWeek, values
                    })
                        ;
                } else {
                    return null;
                }
            }).then(data => {
            setSubmitting(false);
            if (data) {
                alert("排课成功", "success");
                onClose(true);
            }
        })
    }

    return (
        <Dialog open={open} onClose={handleClose} maxWidth={false}>
            <DialogTitle sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 2}}>
                <Typography variant="title">手动排课</Typography>
                <Stack direction="row" alignItems="center" justifyContent="flex-start" spacing={1}>
                    <Chip color="primary" variant="outlined" label={classGroup?.name}/>
                    <Chip color="primary" variant="outlined" label={classGroup?.course.name}/>
                    <Chip color="primary" variant="outlined" label={classGroup?.classroom?.name}/>
                    <Chip icon={<FaceIcon/>} color="primary" variant="outlined" label={classGroup?.teacher?.name}/>
                    <Chip color="secondary" variant="outlined"
                          label={thisWeek ? classGroup?.thisWeek?.start : classGroup?.nextWeek?.start}/>
                    <Chip color="primary" variant="outlined" label={thisWeek ? "本周" : "下周"}/>
                    <Chip color="secondary" variant="outlined"
                          label={thisWeek ? classGroup?.thisWeek?.end : classGroup?.nextWeek?.end}/>
                    <Chip color={published ? "success" : "warning"} variant="outlined"
                          label={published ? "已发布" : `草稿${mode}`}/>
                    <Tooltip title='已销课/待排期/总课时'>
                        <Chip icon={<SignalCellularAlt/>} color="primary" variant="outlined"
                              label={`${classGroup?.confirmedLessons}/${classGroup?.nextLessonNumber}/${classGroup?.course?.lessonCount}`}/>
                    </Tooltip>
                </Stack>
                <Box flexGrow={1}/>
                <IconButton onClick={() => onClose(false)}><CloseIcon/></IconButton>
            </DialogTitle>

            <Card raised sx={{padding: 2, boxSizing: 'border-box'}}>
                <CardContent>
                    <form onSubmit={handleSubmit}>
                        <Stack spacing={2} alignItems="start">
                            {WEEK.map(e =>
                                (!thisWeek || e.index > dayOfWeek) &&
                                <Line key={e.index} dayOfWeek={e} index={e.index} config={config}
                                      workday={workdays[e.index]}
                                      setWorkday={(event, newValue) => {
                                          const newWorkdays = [...workdays];
                                          newWorkdays[e.index] = newValue;
                                          setWorkdays(newWorkdays);
                                      }}
                                      values={values[e.index]}
                                      setValues={(event, vs) => {
                                          const newValues = [...values];
                                          newValues[e.index] = vs;

                                          const count = newValues.reduce((sum, e) => sum + (Array.isArray(e) ? e.length : 0), 0);
                                          if (count > rest) {
                                              alert('课时已满，若要排课，请先取消其他时段课时安排。', 'error');
                                              return;
                                          }

                                          setValues(newValues);
                                      }}
                                      occupiedTimes={occupiedTimes}
                                      disabled={published}
                                />
                            )}

                            {!published &&
                                <Stack direction="row" justifyContent="flex-start" alignItems="center" spacing={2}>
                                    <ToggleButtonGroup color="primary" size="small" value={draft} exclusive={true}
                                                       onChange={(_, v) => setDraft(v)}>
                                        <ToggleButton value={true}>存为草稿</ToggleButton>
                                        <ToggleButton value={false}>正式发布</ToggleButton>
                                    </ToggleButtonGroup>
                                    <LoadingButton
                                        type="submit"
                                        disabled={submitting || !valid}
                                        variant="contained"
                                        color="primary"
                                        startIcon={<Done/>}
                                        sx={{marginTop: "16px"}}
                                        loadingIndicator={<CircularProgress color="inherit" size={24}/>}
                                        loading={submitting}
                                    >提交</LoadingButton>
                                </Stack>}
                        </Stack></form>
                </CardContent>
            </Card>
        </Dialog>
    );
}

export default ManualSchedule;
